package com.gongj.secuity.config;

import java.io.IOException;
import java.io.PrintWriter;
import java.util.HashMap;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AccountExpiredException;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.CredentialsExpiredException;
import org.springframework.security.authentication.DisabledException;
import org.springframework.security.authentication.LockedException;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.security.web.authentication.logout.LogoutSuccessHandler;

import com.fasterxml.jackson.databind.ObjectMapper;

@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Bean
    PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.inMemoryAuthentication()
                .withUser("admin").password("$2a$10$5cfZHg5x9jRNPSHrVnPSE.YEcoqQkfO5IlpxY1R1Jo3u.1JsZPoiW")
                .roles("admin")  //123
                .and()
                .withUser("user").password("$2a$10$TawHx0DjM.trtcCdKumH0uCLqNF7UQVmNbAXi/NXYzv0GDQ6YOU8i")
                .roles("user");  //123
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()       //开启配置
                .antMatchers("/admin/**").hasRole("admin")    //访问/admin/**下的路径，必须具备admin身份
                .antMatchers("/user/**").hasAnyRole("admin", "user")   //访问/user/**下的路径，必须具备admin和user中其中一个身份
                .antMatchers("/db/**").access("hasAnyRole('admin','user')") //访问/db/**下的路径，必须具备admin和user中其中一个身份
                .anyRequest()    //其他请求
                .authenticated()   //已验证   也就是其他请求只需要登录就能访问
                .and()
                .formLogin()  //表单登录
                .loginProcessingUrl("/doLogin")   //登录接口
                .loginPage("/login1")    //登录页面
                .usernameParameter("uname")  //自定义登录key 默认为 username
                .passwordParameter("upwd")     //自定义登录key  默认为 password
                .successHandler(new AuthenticationSuccessHandler() {   //登录成功处理 直接返回json

                    @Override
                    public void onAuthenticationSuccess(HttpServletRequest req, HttpServletResponse res,
                                                        Authentication authentication) throws IOException, ServletException {
                        res.setContentType("application/json;charset=utf-8");
                        PrintWriter out = res.getWriter();
                        HashMap<String, Object> map = new HashMap<String, Object>();
                        map.put("status", 200);
                        map.put("msg", authentication.getPrincipal());
                        out.write(new ObjectMapper().writeValueAsString(map));
                        out.flush();
                        out.close();
                    }
                })   //前后端分离使用
                .failureHandler(new AuthenticationFailureHandler() {   //登录失败处理

                    @Override
                    public void onAuthenticationFailure(HttpServletRequest req, HttpServletResponse resp,
                                                        AuthenticationException e) throws IOException, ServletException {
                        resp.setContentType("application/json;charset=utf-8");
                        PrintWriter out = resp.getWriter();
                        HashMap<String, Object> map = new HashMap<String, Object>();
                        map.put("status", 200);
                        if (e instanceof LockedException) {
                            map.put("msg", "账号被锁定");
                        } else if (e instanceof BadCredentialsException) {
                            map.put("msg", "用户名或者密码错误");
                        } else if (e instanceof DisabledException) {
                            map.put("msg", "账户被禁用");
                        } else if (e instanceof AccountExpiredException) {
                            map.put("msg", "账户过期");
                        } else if (e instanceof CredentialsExpiredException) {
                            map.put("msg", "密码过期");
                        } else {
                            map.put("msg", "登录失败");
                        }
                        out.write(new ObjectMapper().writeValueAsString(map));
                        out.flush();
                        out.close();
                    }
                })
                .permitAll()
                .and()
                .logout()
                .logoutUrl("/logout")
                .logoutSuccessHandler(new LogoutSuccessHandler() {  //注销成功

                    @Override
                    public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse res, Authentication authentication)
                            throws IOException, ServletException {
                        res.setContentType("application/json;charset=utf-8");
                        PrintWriter out = res.getWriter();
                        HashMap<String, Object> map = new HashMap<String, Object>();
                        map.put("status", 200);
                        map.put("msg", "注销成功");
                        out.write(new ObjectMapper().writeValueAsString(map));
                        out.flush();
                        out.close();
                    }
                })
                .and()
                .csrf().disable();


    }


    public static void main(String[] args) {
        BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder();
        System.out.println(bCryptPasswordEncoder.encode("123"));
        System.out.println(bCryptPasswordEncoder.encode("123"));
        System.out.println(bCryptPasswordEncoder.encode("123"));

    }
}
